package concurrecy.lock2;


import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock;

class JannaFairReentrantLock implements Lock {
    // 锁状态：0 未加锁，其他 加锁
    private AtomicInteger state = new AtomicInteger(0);
    // 锁的拥有者
    private AtomicReference owner = new AtomicReference();
    // 等待锁的线程
    private LinkedBlockingQueue<Thread> waiters = new LinkedBlockingQueue<>();

    @Override
    public boolean tryLock() {
        // 当前未被锁定，并且cas从0修改为1，则加锁成功
        if(state.get() == 0 && state.compareAndSet(0, 1)) {
            // 把锁的拥有者修改为当前线程
//            if(owner.compareAndSet(null, Thread.currentThread()))
//                return true;
//            else
//                throw new RuntimeException("modify owner fail, owner:" + owner.get());
//            owner.compareAndSet(null, Thread.currentThread());
            owner.set(Thread.currentThread());
            return true;
        } else {
            // 如果当前线程是锁的拥有者，计数加1
            if(owner.get() == Thread.currentThread()) {
                state.incrementAndGet();
                return true;
            }
        }
        return false;
    }

    @Override
    public void lock() {
        // 如果加锁失败
        if(!waiters.isEmpty() || !tryLock()) {
            Thread current = Thread.currentThread();
            // 加入等待队列
            waiters.add(current);
            for(;;) {
//                // 获取队列头部元素
                Thread first = waiters.peek();
                // 如果当前线程是队列中的第一个，则尝试获取锁
                if(first == Thread.currentThread()) {
                    // 没有获取到，则阻塞
                    if(!tryLock())
                        LockSupport.park();
                    else {
                        // 获取到锁，从队列中移除
                        waiters.remove(first);
                        return;
                    }
                } else {
                    // 不是当前线程，阻塞
                    LockSupport.park();
                }
//                // 抢到了锁
//                if(tryLock()) {
//                    // 从队列中移除
//                    waiters.remove(current);
//                    return;
//                }
//                // 没有抢到锁，阻塞
//                LockSupport.park();
            }
        }
    }

    public boolean tryUnlock() {
        if(owner.get() != Thread.currentThread())
            throw new IllegalMonitorStateException();
        else {
            // 如果释放后，状态为0，说明已经释放完了
            if(state.decrementAndGet() == 0) {
//                if(owner.compareAndSet(Thread.currentThread(), null))
//                    return true;
//                else
//                    throw new RuntimeException("set owner null fail");
                owner.compareAndSet(Thread.currentThread(), null);
//                owner.set(null);
                return true;
            }
        }
        return false;
    }

    @Override
    public void unlock() {
        // 释放成功
        if(tryUnlock()) {
            Thread thread = waiters.peek();
            if(thread != null)
                // 唤醒等待队列中的第一个线程
                LockSupport.unpark(thread);
        }
    }

    @Override
    public void lockInterruptibly() throws InterruptedException {

    }

    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return false;
    }

    @Override
    public Condition newCondition() {
        return null;
    }
}

public class MyFairReentrantLockDemo {
    /**
     * 测试可重入
     * @throws InterruptedException
     */
    static void test1(Lock lock) throws InterruptedException {
        lock.lock();
        System.out.println("第一次加锁成功");

        new Thread(() -> {
            System.out.println("thread 准备获取锁 ...");
            lock.lock();
            System.out.println("thread 加锁成功");
            lock.unlock();
        }).start();

        lock.lock();
        System.out.println("第二次加锁成功");
        Thread.sleep(100);
        lock.unlock();
        System.out.println("释放锁");
        Thread.sleep(100);
        lock.unlock();
        System.out.println("释放锁");
    }

    /**
     * 测试多线程获取锁
     * @param lock
     */
    static void test2(Lock lock) {
        ExecutorService service = Executors.newCachedThreadPool();
        service.execute(new LockChecker(lock));
        service.execute(new LockChecker(lock));
        service.execute(new LockChecker(lock));
        service.execute(new LockChecker(lock));
        service.shutdown();
    }

    /**
     * 测试多线程竞争
     */
    static void test3(Lock lock, int n) throws InterruptedException {
        class Data {
            int x = 0;
        }
        final Data data = new Data();
        ExecutorService executorService = Executors.newCachedThreadPool();
        CountDownLatch latch = new CountDownLatch(n);
        long point = System.currentTimeMillis();
        for (int i = 0; i < n; i++) {
            executorService.execute(() -> {
                for (int j = 0; j < 100_000; j++) {
                    lock.lock();
                    try {
                        data.x ++;
//                        lock.lock();
//                        try {
//                            data.x ++;
//                        } finally {
//                            lock.unlock();
//                        }
                    } finally {
                        lock.unlock();
                    }
                }
                latch.countDown();
            });
        }
        latch.await();
        System.out.println("use " + (System.currentTimeMillis() - point));
        executorService.shutdown();
        System.out.println(data.x);
    }

    public static void main(String[] args) throws InterruptedException {
//        Lock lock = new KaneReentrantLock_Demo();
//        Lock lock = new ReentrantLock(true);
        Lock lock = new JannaFairReentrantLock();
//        test1(lock);
//        test2(lock);
        test3(lock, 8);
    }
}
